package ai.tuobot.sdk

import ai.tuobot.app.BuildConfig
import ai.tuobot.sdk.impl.TuoBotAgentImpl
import ai.tuobot.sdk.inf.TuoBotListener
import ai.tuobot.sdk.model.Character
import ai.tuobot.sdk.model.EventType
import ai.tuobot.sdk.model.LlmOption
import ai.tuobot.sdk.model.TuobotEvent
import ai.tuobot.sdk.model.TuobotMsg
import ai.tuobot.sdk.model.WakeWords
import ai.tuobot.sdk.network.ApiExt
import ai.tuobot.sdk.network.CharacterApi
import ai.tuobot.sdk.network.ConfigApi
import ai.tuobot.sdk.util.StringUtil
import android.content.Context
import android.os.Bundle
import android.util.Log
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File


class TuobotAgent private constructor(
    private val context: Context,
    private val strCfg: String,
    private val tuoBotListener: TuoBotListener
) {
    val TAG = "TuobotAgent"
    private var apiExt: ApiExt
    @Volatile
    private var disposable: Disposable? = null
    private val emptyBundle = Bundle()

    init {
        var base_url = BuildConfig.API_BASE_URL
        if (StringUtil.isValidJson(strCfg)){
            try {
                val cfgJson = JSONObject(strCfg)
                cfgJson.let {
                    if (it.has("server")) {
                        try {
                            val serverObj = it.getJSONObject("server")
                            if (serverObj.has("api_base")){
                                val get_api_base = serverObj.getString("api_base")
                                if (get_api_base.isNotEmpty()) {
                                    if (!((get_api_base.startsWith("https://") || get_api_base.startsWith("http://")))){
                                        base_url = "https://${get_api_base}"
                                    }else if (((get_api_base.startsWith("https://") || get_api_base.startsWith("http://")))){
                                        base_url = get_api_base
                                    }
                                }
                            }
                        } catch (e: JSONException) {
                            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                        }
                    }
                }
            } catch (e: JSONException) {
                e.printStackTrace()
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
            }
        }
        apiExt = ApiExt(base_url)
    }

    companion object {
        private const val TAG = "TuobotAgent"
        @Volatile
        private var tuobotAgent: TuobotAgent? = null
        private var tuoBotAgentImpl: TuoBotAgentImpl? = null


        /**
         * Create tuoboAgent object of singleTon, and auto connect with server
         */
        fun createAgent(
            context: Context,
            str: String,
            tuoBotListener: TuoBotListener
        ): TuobotAgent? {
            if (null == tuobotAgent) {
                synchronized(TuobotAgent::class.java) {
                    if (null == tuobotAgent) {
                        tuobotAgent = TuobotAgent(context, str, tuoBotListener)
                    }
                }
            }
            if (tuoBotAgentImpl == null){
                tuobotAgent?.refreshCharacters()
            }/*else{
                tuoBotAgentImpl?.destroy()
                tuoBotAgentImpl = null
                tuobotAgent?.refreshCharacters()
            }*/
            return tuobotAgent
        }

    }

    private fun refreshCharacters() {
        disposable?.dispose()
        disposable = apiExt.api(CharacterApi::class.java).getCharacters().subscribeOn(Schedulers.io()).doOnError {
        }.subscribe(
            {
                val resp: List<Character>? = it?.mapIndexed{ idx, v -> v.copy(id = "god${if (idx == 0) "" else idx}") }
                resp?.let{
                    var characterIndex = 0 // 选择的角色索引

                    if (StringUtil.isValidJson(strCfg)) {
                        try {
                            val cfgJson = JSONObject(strCfg)
                            cfgJson.let {
                                if (it.has("session")) {
                                    try {
                                        val sessionObj = it.getJSONObject("session")
                                        if (sessionObj.has("language")){
                                            val language = sessionObj.getString("language")
                                            if (language.isNotEmpty() && language.equals("cn")){
                                                characterIndex = 1
                                            }
                                        }
                                    } catch (e: JSONException) {
                                        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                                    }
                                }
                            }
                        } catch (e: JSONException) {
                            e.printStackTrace()
                        }
                    }


                    if (it.size > characterIndex){
                        // 设置大模型自定义参数
                        if (!strCfg.contains("userparams") || !StringUtil.isValidJson(strCfg)){
                            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                            return@let
                        }
                        if (!(strCfg.contains("access_token") && strCfg.contains("device_id") && strCfg.contains("family_id"))){
                            tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_PARAM_ERROR, emptyBundle))
                            return@let
                        }
                        val userparams = StringUtil.getJsonPeaceByAndWithTag("userparams", strCfg)
                        // 将字符串转换为 RequestBody
                        val requestBody: RequestBody = userparams.toRequestBody("application/json".toMediaTypeOrNull())
                        apiExt.api(ConfigApi::class.java).setUserParams(requestBody).enqueue(object :
                            Callback<JSONObject> {
                            override fun onResponse(
                                call: Call<JSONObject>,
                                response: Response<JSONObject>
                            ) {
                                Log.d(TAG,"set userparams onResponse")
                                if (response.isSuccessful) {
                                    tuoBotAgentImpl = TuoBotAgentImpl(context, strCfg, it.get(characterIndex), tuoBotListener)
                                    WakeWords.words.clear()
                                    WakeWords.words.add("alice")
                                    WakeWords.words.add("amy")
                                }else{
                                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_SERVER_ERROR, emptyBundle))
                                }
                            }

                            override fun onFailure(call: Call<JSONObject>, t: Throwable) {
                                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_SERVER_ERROR, emptyBundle))
                            }

                        })
                    }else{
                        tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_CONNECT_ERROR, emptyBundle))
                    }
                }

            },{ error ->
                // Handle error - display errormessage, retry, etc.
                if (error is HttpException) {
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_SERVER_ERROR, emptyBundle))
                    // Handle HTTP error codes
                    when (error.code()) {
                        502 -> { /* Handle Bad Gateway error */ }
                        // ... handle other HTTP error codes
                    }
                } else {
                    // Handle other errors
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_CONNECT_ERROR, emptyBundle))
                }
            }
        )
    }

    /**
     * 更新模型参数
     */
    fun updateUserParames(userparams:String){
        // 将字符串转换为 RequestBody
        val requestBody: RequestBody = userparams.toRequestBody("application/json".toMediaTypeOrNull())
        apiExt.api(ConfigApi::class.java).setUserParams(requestBody).enqueue(object :
            Callback<JSONObject> {
            override fun onResponse(
                call: Call<JSONObject>,
                response: Response<JSONObject>
            ) {
                Log.d(TAG,"update userparams onResponse: $userparams")
                if (response.isSuccessful) {
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_UPDATE_USER_PARAM_OK, emptyBundle))
                }else{
                    tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_UPDATE_USER_PARAM_FAILURE, emptyBundle))
                }
            }
            override fun onFailure(call: Call<JSONObject>, t: Throwable) {
                tuoBotListener.onEvent(TuobotEvent(EventType.EVENT_UPDATE_USER_PARAM_FAILURE, emptyBundle))
            }

        })
    }

    /**
     * play mp3 audio of ByteArray
     */
    fun playMp3Audio(mp3Data: ByteArray) {
        tuoBotAgentImpl?.playMp3Audio(mp3Data)
    }

    /**
     * play audio file
     */
    fun playAudioFile(file: File) {
        tuoBotAgentImpl?.playAudioFile(file)
    }

    /**
     * eg:
     * val bundle = Bundle()
     * bundle.putString("text","input msg info here")
     * tuobotAgent?.sendMsg(TuobotMsg(MsgType.MSG_CHAT, bundle))
     */
    fun sendMsg(tuobotMsg: TuobotMsg) {
        tuoBotAgentImpl?.sendMsg(tuobotMsg)
    }

    /**
     * Reconnect with the server
     */
    fun reConnect(){
        if (tuoBotAgentImpl == null){
            tuobotAgent?.refreshCharacters()
        }else{
            tuoBotAgentImpl?.reConnect()
        }
    }

    /**
     * Disconnect with the server
     */
    fun disConnect(){
        tuoBotAgentImpl?.disConnect()
    }

    /**
     * Disconnect with server and destroy related resources
     */
    fun destroy() {
        disConnect()
        tuoBotAgentImpl?.destroy()
        tuoBotAgentImpl = null
        tuobotAgent = null
        disposable?.dispose()
        disposable = null
    }

    /**
     *  Mute audio recorder
     */
    fun setMute(mute: Boolean) {
        tuoBotAgentImpl?.setMute(mute)
    }

    /**
     *  Stop play current audio
     */
    fun stopPlayAudio(){
        tuoBotAgentImpl?.stopPlayAudio()
    }

    /**
     *  Set the current wake state to sleep
     */

    fun sleep(){
        tuoBotAgentImpl?.sleep()
    }

    fun reSendPreAudio(){
        tuoBotAgentImpl?.reSendPreAudio()
    }

    fun sendAudioFile(file: File){
        tuoBotAgentImpl?.sendAudioFile(file)
    }

    fun getLastAudioFile(): File? {
        return tuoBotAgentImpl?.getLastAudioFile()
    }

}
